using System;
using System.Drawing;
using System.IO;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Reflection;
using needle.UI.Controls.Flat.Utilities;
using needle.UI.Controls.Flat.Utilities.Win32;

namespace needle.UI.Controls.Flat.Windows.Forms.Helpers
{
	internal class GraphicsUtils   
	{
		protected static IntPtr mhalfToneBrush = IntPtr.Zero;

		#region Nested types

		public enum CommandState
		{
			Normal,
			HotTrack,
			Pushed
		}

		#endregion
		
		#region Constructors

		private GraphicsUtils()
		{
		}

		#endregion

		#region Methods

		public static Bitmap GetTileBitmap(Rectangle rcDest, Bitmap bitmap)
		{
			Bitmap tiledBitmap = new Bitmap(rcDest.Width, rcDest.Height);
			using ( Graphics g = Graphics.FromImage(tiledBitmap) )
			{
				for ( int i = 0; i < tiledBitmap.Width; i += bitmap.Width )
				{
					for ( int j = 0; j < tiledBitmap.Height; j += bitmap.Height )
					{
						g.DrawImage(bitmap, new Point(i, j));					

					}
				}
			}
			return tiledBitmap;
		}

		public static void DrawArrowGlyph(Graphics g, Rectangle rc, needle.UI.Controls.Flat.Windows.Forms.ArrowGlyph arrowGlyph, Brush brush)
		{
			DrawArrowGlyph(g, rc, 5, 3, arrowGlyph, brush);
		}

		public static void DrawArrowGlyph(Graphics g, Rectangle rc, int arrowWidth, int arrowHeight, needle.UI.Controls.Flat.Windows.Forms.ArrowGlyph arrowGlyph, Brush brush)
		{
			Point[] pts = new Point[3];
			int yMiddle = rc.Top + rc.Height/2-arrowHeight/2+1;
			int xMiddle = rc.Left + rc.Width/2;
			
			if ( arrowGlyph == needle.UI.Controls.Flat.Windows.Forms.ArrowGlyph.Up )
			{
				pts[0] = new Point(xMiddle, yMiddle-2);
				pts[1] = new Point(xMiddle-arrowWidth/2-1, yMiddle+arrowHeight-1);
				pts[2] = new Point(xMiddle+arrowWidth/2+1,  yMiddle+arrowHeight-1);
				
			}
			else if ( arrowGlyph == needle.UI.Controls.Flat.Windows.Forms.ArrowGlyph.Down )
			{
				pts[0] = new Point(xMiddle-arrowWidth/2, yMiddle);
				pts[1] = new Point(xMiddle+arrowWidth/2+1,  yMiddle);
				pts[2] = new Point(xMiddle, yMiddle+arrowHeight);
			}
			else if ( arrowGlyph == needle.UI.Controls.Flat.Windows.Forms.ArrowGlyph.Left )
			{
				yMiddle = rc.Top + rc.Height/2;
				pts[0] = new Point(xMiddle-arrowHeight/2,  yMiddle);
				pts[1] = new Point(pts[0].X+arrowHeight, yMiddle-arrowWidth/2-1);
				pts[2] = new Point(pts[0].X+arrowHeight,  yMiddle+arrowWidth/2+1);

			}
			else if ( arrowGlyph == needle.UI.Controls.Flat.Windows.Forms.ArrowGlyph.Right )
			{
				yMiddle = rc.Top + rc.Height/2;
				pts[0] = new Point(xMiddle+arrowHeight/2+1,  yMiddle);
				pts[1] = new Point(pts[0].X-arrowHeight, yMiddle-arrowWidth/2-1);
				pts[2] = new Point(pts[0].X-arrowHeight,  yMiddle+arrowWidth/2+1);
			}

			g.FillPolygon(brush, pts);
		}

		public static void DrawButton(Graphics g,Color buttonColor, Color buttonHotColor, Color buttonPressedColor, Color borderColor, Color borderHotColor, Rectangle buttonRect,bool border_hot,bool btn_hot,bool btn_pressed)
		{
			if(btn_hot)
			{
				if(btn_pressed)
				{
					using (Brush brush = new SolidBrush(buttonPressedColor))
					{
						g.FillRectangle(brush,buttonRect);
					}
				}
				else
				{
					using (Brush brush = new SolidBrush(buttonHotColor))
					{
						g.FillRectangle(brush,buttonRect);
					}
				}
			}
			else
			{
				using (Brush brush = new SolidBrush(buttonColor))
				{
					g.FillRectangle(brush,buttonRect);
				}
			}

			buttonRect = new Rectangle(buttonRect.X-1,buttonRect.Y-1,buttonRect.Width+1,buttonRect.Height+1);
			if(border_hot || btn_hot || btn_pressed)
			{
				using (Pen pen = new Pen(borderHotColor))
				{
					g.DrawRectangle(pen,buttonRect);
				}
			}
			else
			{
				using (Pen pen = new Pen(borderColor))
				{
					g.DrawRectangle(pen,buttonRect);
				}
			}
		}

		public static void DrawBorder(Graphics g, Color borderColor, Color borderHotColor,Rectangle controlRect,bool hot)
		{
			controlRect = new Rectangle(controlRect.X,controlRect.Y,controlRect.Width - 1,controlRect.Height - 1);

			if(hot)
			{
				using (Pen pen = new Pen(borderHotColor))
				{
					g.DrawRectangle(pen,controlRect);
				}
			}
			else
			{
				using (Pen pen = new Pen(borderColor))
				{
					g.DrawRectangle(pen,controlRect);
				}
			}
		}

		public static Icon LoadIcon(string iconName)
		{
            Stream strm = Type.GetType("needle.UI.Controls.Flat.Windows.Forms.Helpers.GraphicsUtils").Assembly.GetManifestResourceStream("needle.Controls.Flat.Windows.Forms.Resources." + iconName);

			Icon ic = null;
			if(strm != null)
			{
				ic = new System.Drawing.Icon(strm);
				strm.Close();
			}

			return ic;
		}

		public static Image LoadImage(string imageName)
		{			
			Stream strm = Type.GetType("needle.UI.Controls.Flat.Windows.Forms.Helpers.GraphicsUtils").Assembly.GetManifestResourceStream("needle.Controls.Flat.Windows.Forms.Resources." + imageName);

			Image im = null;
			if(strm != null)
			{
				im = new System.Drawing.Bitmap(strm);
				strm.Close();
			}

			return im;
		}

		public static void DrawPlainRaisedBorderTopOrBottom(Graphics g, 
			Rectangle rect,
			Color lightLight, 
			Color baseColor,
			Color dark, 
			Color darkDark,
			bool drawTop)
		{
			if ((rect.Width > 2) && (rect.Height > 2))
			{
				using(Pen ll = new Pen(lightLight),
						  b = new Pen(baseColor),
						  d = new Pen(dark),
						  dd = new Pen(darkDark))
				{
					int left = rect.Left;
					int top = rect.Top;
					int right = rect.Right;
					int bottom = rect.Bottom;

					if (drawTop)
					{
						g.DrawLine(b, right-1, top, left, top);
						g.DrawLine(ll, right-1, top+1, left, top+1);
						g.DrawLine(b, right-1, top+2, left, top+2);
					}
					else
					{
						g.DrawLine(dd, right-1, bottom-1, left, bottom-1);
						g.DrawLine(d, right-1, bottom-2, left, bottom-2);
						g.DrawLine(b, right-1, bottom-3, left, bottom-3);
					}
				}
			}
		}

		public static void DrawPlainRaisedBorder(Graphics g, 
			Rectangle rect,
			Color lightLight, 
			Color baseColor,
			Color dark, 
			Color darkDark)
		{
			if ((rect.Width > 2) && (rect.Height > 2))
			{
				using(Pen ll = new Pen(lightLight),
						  b = new Pen(baseColor),
						  d = new Pen(dark),
						  dd = new Pen(darkDark))
				{
					int left = rect.Left;
					int top = rect.Top;
					int right = rect.Right;
					int bottom = rect.Bottom;

					g.DrawLine(b, right-1, top, left, top);
					g.DrawLine(ll, right-2, top+1, left+1, top+1);
					g.DrawLine(b, right-3, top+2, left+2, top+2);

					g.DrawLine(b, left, top, left, bottom-1);
					g.DrawLine(ll, left+1, top+1, left+1, bottom-2);
					g.DrawLine(b, left+2, top+2, left+2, bottom-3);
					
					g.DrawLine(dd, right-1, top+1, right-1, bottom-1);
					g.DrawLine(d, right-2, top+2, right-2, bottom-2);
					g.DrawLine(b, right-3, top+3, right-3, bottom-3);

					g.DrawLine(dd, right-1, bottom-1, left, bottom-1);
					g.DrawLine(d, right-2, bottom-2, left+1, bottom-2);
					g.DrawLine(b, right-3, bottom-3, left+2, bottom-3);
				}
			}
		}

		public static void DrawPlainSunkenBorderTopOrBottom(Graphics g, 
			Rectangle rect,
			Color lightLight, 
			Color baseColor,
			Color dark, 
			Color darkDark,
			bool drawTop)
		{
			if ((rect.Width > 2) && (rect.Height > 2))
			{
				using(Pen ll = new Pen(lightLight),
						  b = new Pen(baseColor),
						  d = new Pen(dark),
						  dd = new Pen(darkDark))
				{
					int left = rect.Left;
					int top = rect.Top;
					int right = rect.Right;
					int bottom = rect.Bottom;

					if (drawTop)
					{
						g.DrawLine(d, right-1, top, left, top);
						g.DrawLine(dd, right-1, top+1, left, top+1);
						g.DrawLine(b, right-1, top+2, left, top+2);
					}
					else
					{
						g.DrawLine(ll, right-1, bottom-1, left, bottom-1);
						g.DrawLine(b, right-1, bottom-2, left, bottom-2);
						g.DrawLine(b, right-1, bottom-3, left, bottom-3);
					}
				}
			}
		}

		public static void DrawPlainSunkenBorder(Graphics g, 
			Rectangle rect,
			Color lightLight, 
			Color baseColor,
			Color dark, 
			Color darkDark)
		{
			if ((rect.Width > 2) && (rect.Height > 2))
			{
				using(Pen ll = new Pen(lightLight),
						  b = new Pen(baseColor),
						  d = new Pen(dark),
						  dd = new Pen(darkDark))
				{
					int left = rect.Left;
					int top = rect.Top;
					int right = rect.Right;
					int bottom = rect.Bottom;

					g.DrawLine(d, right-1, top, left, top);
					g.DrawLine(dd, right-2, top+1, left+1, top+1);
					g.DrawLine(b, right-3, top+2, left+2, top+2);

					g.DrawLine(d, left, top, left, bottom-1);
					g.DrawLine(dd, left+1, top+1, left+1, bottom-2);
					g.DrawLine(b, left+2, top+2, left+2, bottom-3);
					
					g.DrawLine(ll, right-1, top+1, right-1, bottom-1);
					g.DrawLine(b, right-2, top+2, right-2, bottom-2);
					g.DrawLine(b, right-3, top+3, right-3, bottom-3);

					g.DrawLine(ll, right-1, bottom-1, left, bottom-1);
					g.DrawLine(b, right-2, bottom-2, left+1, bottom-2);
					g.DrawLine(b, right-3, bottom-3, left+2, bottom-3);
				}
			}
		}

		public static void DrawDragRectangle(Rectangle newRect, int indent)
		{
			DrawDragRectangles(new Rectangle[]{newRect}, indent);
		}

		[UseApiElements("CombineRgn, DeleteObject, GetDC, ReleaseDC, SelectClipRgn, RECT, GetClipBox")]
		public static void DrawDragRectangles(Rectangle[] newRects, int indent)
		{
			if (newRects.Length > 0)
			{
				IntPtr newRegion = CreateRectangleRegion(newRects[0], indent);

				for(int index=1; index<newRects.Length; index++)
				{
					IntPtr extraRegion = CreateRectangleRegion(newRects[index], indent);
					
					Gdi32.CombineRgn(newRegion, newRegion, extraRegion, (int)CombineFlags.RGN_XOR);

					Gdi32.DeleteObject(extraRegion);
				}

				IntPtr hDC = User32.GetDC(IntPtr.Zero);

				Gdi32.SelectClipRgn(hDC, newRegion);

				RECT rectBox = new RECT();
				 
				Gdi32.GetClipBox(hDC, ref rectBox);

				IntPtr brushHandler = GetHalfToneBrush();

				IntPtr oldHandle = Gdi32.SelectObject(hDC, brushHandler);

				Gdi32.PatBlt(hDC, 
					rectBox.left, 
					rectBox.top, 
					rectBox.right - rectBox.left, 
					rectBox.bottom - rectBox.top, 
					(int)RasterOperations.PATINVERT);

				Gdi32.SelectObject(hDC, oldHandle);

				Gdi32.SelectClipRgn(hDC, IntPtr.Zero);

				Gdi32.DeleteObject(newRegion);

				User32.ReleaseDC(IntPtr.Zero, hDC);
			}
		}

		[UseApiElements("RECT, CreateRectRgnIndirect, CombineFlags.RGN_XOR")]
		protected static IntPtr CreateRectangleRegion(Rectangle rect, int indent)
		{
			RECT newWinRect = new RECT();
			newWinRect.left = rect.Left;
			newWinRect.top = rect.Top;
			newWinRect.right = rect.Right;
			newWinRect.bottom = rect.Bottom;

			IntPtr newOuter = Gdi32.CreateRectRgnIndirect(ref newWinRect);

			if ((indent <= 0) || (rect.Width <= indent) || (rect.Height <= indent))
				return newOuter;

			newWinRect.left += indent;
			newWinRect.top += indent;
			newWinRect.right -= indent;
			newWinRect.bottom -= indent;

			IntPtr newInner = Gdi32.CreateRectRgnIndirect(ref newWinRect);

			RECT emptyWinRect = new RECT();
			emptyWinRect.left = 0;
			emptyWinRect.top = 0;
			emptyWinRect.right = 0;
			emptyWinRect.bottom = 0;

			IntPtr newRegion = Gdi32.CreateRectRgnIndirect(ref emptyWinRect);

			Gdi32.CombineRgn(newRegion, newOuter, newInner, (int)CombineFlags.RGN_XOR);

			Gdi32.DeleteObject(newOuter);
			Gdi32.DeleteObject(newInner);

			return newRegion;
		}

		[UseApiElements("LogBrush, CreateBrushIndirect")]
		protected static IntPtr GetHalfToneBrush()
		{
			if (mhalfToneBrush == IntPtr.Zero)
			{	
				Bitmap bitmap = new Bitmap(8,8,PixelFormat.Format32bppArgb);

				Color white = Color.FromArgb(255,255,255,255);
				Color black = Color.FromArgb(255,0,0,0);

				bool flag=true;

				for(int x=0; x<8; x++, flag = !flag)
					for(int y=0; y<8; y++, flag = !flag)
						bitmap.SetPixel(x, y, (flag ? white : black));

				IntPtr hBitmap = bitmap.GetHbitmap();

				LOGBRUSH brush = new LOGBRUSH();

				brush.lbStyle = (int)BrushStyles.BS_PATTERN;
				brush.lbHatch = (int)hBitmap;

				mhalfToneBrush = Gdi32.CreateBrushIndirect(ref brush);
			}

			return mhalfToneBrush;
		}

		#endregion
	}
}